package model;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import parameter.ParameterItineraire;
import referential.Position;
import control.StatRejet;

/**
 * Un itineraire represente un parcours à realiser pour une équipe
 * @author Florian
 *
 */
public class Itineraire implements ParameterItineraire{
  /**
   * Un parcours décrit une liste de CheckPoint par lequels passer
   */
  List<CheckPoint> parcours = new ArrayList<CheckPoint>();
  int nbEtape = 0;
  double distanceTotale = 0;
  int numero;
  
  
  public Itineraire(int numero) {
    super();
    this.numero = numero;
  }

  public Itineraire() {
    super();
  }
  
  /**
   * Ajoute une etape à l'itineraire et mets à jour la liste des passage de l'étape
   * @param checkPoint
   */
  public void ajouterEtape(CheckPoint checkPoint) {
    parcours.add(checkPoint);
    checkPoint.ajouterPassage(this);
    nbEtape++;
  }
  
  public void substituer(Groupe g, CheckPoint cc, int position) {
    parcours.remove(position);
    parcours.add(position, cc);
    
  }
  
  public void ajouterEtapeSansBooking(CheckPoint checkPoint) {
    parcours.add(checkPoint);
    nbEtape++;
  }

  /**
   * Methode de controle pour definir sur un itineraire repond au chaier des charge (durée, distance, interet, etc..)
   * @return : true si l'ittineraire est valable, false sinon
   */
  public boolean estAcceptable(StatRejet stat) {
    // VErification des etapes d'etapes
    int numeroEtape = 0;
    int nombreAlternanceRythme = 0;
    boolean activitePrecedenteStimulente = false;
    for(Iterator<CheckPoint> it = parcours.iterator(); it.hasNext();) {
      CheckPoint etape = it.next();
      if(!etape.respecteLesQuotas(numeroEtape)) {
        stat.log("QUOTA_MAX");
        return false;
      }
      if(FILTRE_ACTIVITE_PROXIMITE_ACTIF && ((numeroEtape == 0 || numeroEtape == NB_CHECK_POINT_PAR_ITINERAIRE-1) && !etape.isProximite())) {
        stat.log("PROXIMITE");
        return false;
      }
      if (numeroEtape != 0 && activitePrecedenteStimulente != etape.isStimulante()) {
        nombreAlternanceRythme++;
      }
      activitePrecedenteStimulente = etape.isStimulante();
      numeroEtape++;
    }
    
    if (nombreAlternanceRythme < NB_ALTERNANCE_RYTHME_MIN) {
      stat.log("ALTERNANCE_RYTME");
      return false;
    }
    
    // Mesure de la distance et durée
    double distanceTotale = 0;
    CheckPoint etapePrecedente = null;
    
    // distance entre deux points
    for(Iterator<CheckPoint> it = parcours.iterator(); it.hasNext();) {
      CheckPoint etape = it.next();
      if (etapePrecedente != null) {
        Position pEtape = etape.getPosition();
        Position pEtapePrecedente = etapePrecedente.getPosition();
        double distance = pEtape.getDistance(pEtapePrecedente);
        if (!(distance >= DISTANCE_MIN_ENTRE_DEUX_CHECKPOINT && distance <= DISTANCE_MAX_ENTRE_DEUX_CHECKPOINT)){
          stat.log("DISTANCE_2_POINT");
          return false;
        }
        distanceTotale += distance;
      }
      etapePrecedente = etape;
    }
    
    this.setDistanceTotale(distanceTotale);
    // distance totale
    if (!(distanceTotale >= DISTANCE_MIN_TOTALE && distanceTotale <= DISTANCE_MAX_TOTALE)){
      stat.log("DISTANCE_TOTALE");
      return false;
    }
    
    return true;
  }

  public int getNbEtape() {
    return nbEtape;
  }
  
  public String toString() {
    StringBuffer resultat = new StringBuffer();
    resultat.append("Distance totale : ").append(this.getDistanceTotale()).append("\n");
    for (Iterator<CheckPoint> it = parcours.iterator(); it.hasNext();) {
      CheckPoint c = it.next();
      resultat.append("etape : ").append(c).append("\t");
    }
    resultat.append("\n");
    return resultat.toString();
  }

  public String toCSV() {
    StringBuffer resultat = new StringBuffer();
    for (Iterator<CheckPoint> it = parcours.iterator(); it.hasNext();) {
      CheckPoint c = it.next();
      resultat.append(c.getId()).append(" - ").append(c.getTitreActivité()).append(CSV_CELL_DELIMITER);
    }
    resultat.append("Distance totale : ").append(CSV_CELL_DELIMITER).append(this.getDistanceTotale());
    resultat.append(CSV_LINE_DELIMITER);
    return resultat.toString();
  }
  
  public String toSQL() {
    StringBuffer resultat = new StringBuffer();
    resultat.append("INSERT INTO itineraire (id, nom, distance) VALUES (").append(getNumero()).append(", 'itineraire numero ").append(getNumero()).append("',").append(getDistanceTotale()).append(");").append(CSV_LINE_DELIMITER);
    int i = 0;
    for (Iterator<CheckPoint> it = parcours.iterator(); it.hasNext();) {
      CheckPoint c = it.next();
      resultat.append("INSERT INTO etapes (id_itineraire, id_checkpoint, position) VALUES (").append(getNumero()).append(",").append(c.getId()).append(",").append(i++).append(");").append(CSV_LINE_DELIMITER);
    }
    resultat.append(CSV_LINE_DELIMITER);
    return resultat.toString();
  }
  
  public double getDistanceTotale() {
    return distanceTotale;
  }

  public void setDistanceTotale(double distanceTotale) {
    this.distanceTotale = distanceTotale;
  }

  public void retirerLesPassages() {
    int etape = 0;
    for (Iterator<CheckPoint> it = parcours.iterator(); it.hasNext();) {
      CheckPoint c = it.next();
      c.retirerPassage(this, etape);
      etape++;
    }
    
  }

  public boolean estUneCominaisonAcceptable(StatRejet stat) {
    
    // Mesure de la distance et durée
    CheckPoint etapePrecedente = null;
    int dureeTotale = 0;
    boolean activitéLonguePrevue = false;
    boolean activitéOriginalePrevue = false;
    int nombreActiviteEuropeenPrévue = 0;
    boolean activitéInterpelleationPassants = false;
    boolean activitéCreative = false;
    int nombreActivitéPhysique = 0;
    boolean activitéConfrontationPrévue = false;
    boolean activitéCooperationPrévue = false;
    int nombreActivitéTheatre = 0;
    boolean activitéMobilisationPrevue = false;
    
    
    // distance entre deux points
    for(Iterator<CheckPoint> it = parcours.iterator(); it.hasNext();) {
      CheckPoint etape = it.next();
      if (etapePrecedente != null) {
        if (etape.estUneActiviteLongue()) {
          if (activitéLonguePrevue) {
            stat.log("COMB_2_ACTIVITES_LONGUES");
            return false;
          }
          activitéLonguePrevue = true;
        }
        
        if (etape.estUneActivitéOriginal()) {
          activitéOriginalePrevue = true;
        }
        
        if (etape.estUneActivitéEuropeene()) {
          nombreActiviteEuropeenPrévue++;
        }
        
        if (etape.isInteraction()) {
          activitéInterpelleationPassants = true;
        }
        
        if (etape.isCreatif()) {
          activitéCreative = true;
        }
        
        if (etape.isPhysique()) {
          nombreActivitéPhysique++;
        }
        
        if (etape.isConfrontation()) {
          activitéConfrontationPrévue = true;
        }
        
        if (!etape.isConfrontation() && etape.getNombreEquipe() >= 2) {
          activitéCooperationPrévue = true;
        }
        
        if (etape.isTheatre()) {
          nombreActivitéTheatre++;
        }
        
        if (etape.isMobilisation()) {
          activitéMobilisationPrevue = true;
        }
      }
      etapePrecedente = etape;
    }
    
    if (!(dureeTotale >= DUREE_MIN_TOTALE && dureeTotale <= DUREE_MAX_TOTALE) ) {
      stat.log("COMB_DUREE");
      return false;
    }
    
    if (FILTRE_ACTIVITE_LONGUE_ACTIF && !activitéLonguePrevue) {
      stat.log("COMB_PAS_ACTIVITE_LONGUE");
      return false;
    }
    
    if (!activitéOriginalePrevue) {
      stat.log("COMB_ORIGINALE");
      return false;
    }
    
    if (FILTRE_ACTIVITE_INTERPELLATION_ACTIF && !activitéInterpelleationPassants && !activitéLonguePrevue) {
      stat.log("COMB_INTERPELLATION");
      return false;
    }
    
    if (FILTRE_ACTIVITE_CREATIVE_ACTIF && !activitéCreative) {
      stat.log("COMB_CREATIF");
      return false;
    }
    if (nombreActiviteEuropeenPrévue < NB_MIN_ACTIVITE_EUROPEENE-1) {
      stat.log("COMB_EUROPEEN");
      return false;
    }
    
    if (!(nombreActivitéPhysique >= NB_MIN_ACTIVITE_PHYSIQUE && nombreActivitéPhysique < NB_MAX_ACTIVITE_PHYSIQUE) ) {
      stat.log("COMB_PHYSIQUE");
      return false;
    }
    
    if (!activitéConfrontationPrévue) {
      stat.log("COMB_CONFRONTATION");
      return false;
    }
    
    if (!activitéCooperationPrévue) {
      stat.log("COMB_COOPERATION");
      return false;
    }
    
    if (!activitéMobilisationPrevue) {
      stat.log("COMB_MOBILISATION");
      return false;
    }
    
    if (!(nombreActivitéTheatre >= NB_MIN_ACTIVITE_THEATRE && nombreActivitéTheatre < NB_MAX_ACTIVITE_THEATRE) ) {
      stat.log("COMB_THEATRE");
      return false;
    }
    
    return true;
  }

  public boolean estUneCominaisonFinaleAcceptable(StatRejet stat) {
    
    // Mesure de la distance et durée
    CheckPoint etapePrecedente = null;
    int dureeTotale = 0;
    boolean activitéLonguePrevue = false;
    boolean activitéOriginalePrevue = false;
    boolean activitéRegionalePrevue = false;
    int nombreActiviteEuropeenPrévue = 0;
    boolean activitéInterpelleationPassants = false;
    boolean activitéVivreEnsemble = false;
    boolean activitéInstitution = false;
    boolean activitéCreative = false;
    int nombreActivitéPhysique = 0;
    boolean activitéConfrontationPrévue = false;
    boolean activitéCooperationPrévue = false;
    int nombreActivitéTheatre = 0;
    boolean activitéMobilisationPrevue = false;
    
    
    // distance entre deux points
    for(Iterator<CheckPoint> it = parcours.iterator(); it.hasNext();) {
      CheckPoint etape = it.next();
      
      if (!etape.isFullBooked()) {
        stat.log("COMB2_FULL_BOOKED");
        return false;
      }
      
      if (etapePrecedente != null) {
        if (etape.estUneActiviteLongue()) {
          if (activitéLonguePrevue) {
            stat.log("COMB2_2_ACTIVITES_LONGUES");
            return false;
          }
          activitéLonguePrevue = true;
        }
        
        if (etape.estUneActivitéOriginal()) {
          activitéOriginalePrevue = true;
        }
        
        if (etape.isRegionnal()) {
          activitéRegionalePrevue =true;
        }
        if (etape.estUneActivitéEuropeene()) {
          nombreActiviteEuropeenPrévue++;
        }
        
        if (etape.isInteraction()) {
          activitéInterpelleationPassants = true;
        }
        
        if (etape.isVivreEnsemble()) {
          activitéVivreEnsemble = true;
        }
        
        if (etape.isInstitution()) {
          activitéInstitution = true;
        }
        
        if (etape.isCreatif()) {
          activitéCreative = true;
        }
        
        if (etape.isPhysique()) {
          nombreActivitéPhysique++;
        }
        
        if (etape.isConfrontation()) {
          activitéConfrontationPrévue = true;
        }
        
        if (!etape.isConfrontation() && etape.getNombreEquipe() >= 2) {
          activitéCooperationPrévue = true;
        }
        
        if (etape.isTheatre()) {
          nombreActivitéTheatre++;
        }
        
        if (etape.isMobilisation()) {
          activitéMobilisationPrevue = true;
        }
      }
      etapePrecedente = etape;
    }
    
    if (!(dureeTotale >= DUREE_MIN_TOTALE && dureeTotale <= DUREE_MAX_TOTALE) ) {
      stat.log("COMB2_DUREE");
      return false;
    }
    
    /*if (!activitéLonguePrevue) {
      stat.log("COMB_PAS_ACTIVITE_LONGUE");
      return false;
    }*/
    
    if (FILTRE_ACTIVITE_REGIONALE_ACTIF && !activitéRegionalePrevue) {
      stat.log("COMB2_REGIONALE");
      return false;
    }
    
    if (!activitéOriginalePrevue) {
      stat.log("COMB_ORIGINALE");
      return false;
    }
    
    if (FILTRE_ACTIVITE_INTERPELLATION_ACTIF && !activitéInterpelleationPassants) {
      stat.log("COMB2_INTERPELLATION");
      return false;
    }
    
    if (FILTRE_ACTIVITE_VIVRE_ENSEMBLE_ACTIF && !activitéVivreEnsemble) {
      stat.log("COMB2_VIVRE_ENSEMBLE");
      return false;
    }
    
    if (FILTRE_ACTIVITE_INSTITUTION_ACTIF && !activitéInstitution) {
      stat.log("COMB_INSTITUTION");
      return false;
    }
    
    if (FILTRE_ACTIVITE_CREATIVE_ACTIF && !activitéCreative) {
      stat.log("COMB2_CREATIF");
      return false;
    }
    if (nombreActiviteEuropeenPrévue < NB_MIN_ACTIVITE_EUROPEENE) {
      stat.log("COMB2_EUROPEEN");
      return false;
    }
    
    if (!(nombreActivitéPhysique >= NB_MIN_ACTIVITE_PHYSIQUE && nombreActivitéPhysique < NB_MAX_ACTIVITE_PHYSIQUE) ) {
      stat.log("COMB2_PHYSIQUE");
      return false;
    }
    
    if (!activitéConfrontationPrévue) {
      stat.log("COMB2_CONFRONTATION");
      return false;
    }
    
    if (!activitéCooperationPrévue) {
      stat.log("COMB2_COOPERATION");
      return false;
    }
    
    if (!activitéMobilisationPrevue) {
      stat.log("COMB2_MOBILISATION");
      return false;
    }
    
    if (!(nombreActivitéTheatre >= NB_MIN_ACTIVITE_THEATRE && nombreActivitéTheatre < NB_MAX_ACTIVITE_THEATRE) ) {
      stat.log("COMB2_THEATRE");
      return false;
    }
    
    return true;
  }
  
  public int getNumero() {
    return numero;
  }

  public int[] getListInt() {
    int[] resulat = new int[NB_CHECK_POINT_PAR_ITINERAIRE];
    int i = 0;
    HashSet<Integer> setControl = new HashSet<Integer>();
    for (Iterator<CheckPoint> it = parcours.iterator(); it.hasNext();) {
      CheckPoint c = it.next();
      resulat[i++] = c.getId();
      setControl.add(c.getId());
    }
    if (setControl.size() != NB_CHECK_POINT_PAR_ITINERAIRE) {
      System.out.println(Arrays.toString(resulat));
    }
    return resulat;
  }
  
  public List<CheckPoint> getParcours() {
    return parcours;
  }

 

}
